﻿using System;
using System.Collections.Generic;
using SobrietyEngine.Common;
using SobrietyEngine.Scene;
using Microsoft.Xna.Framework;

namespace SobrietyEngine.Actor
{
    public class ActorFactory
    {
        static private Dictionary<String, IActorBuilder> ByTypeString = null;
        static private Dictionary<String, String> AliasToTypeString = null;

        public static void Register(Type type, IActorBuilder builder)
        {
            String strType = type.ToString();
            String className = builder.GetAlias();

            //special case for the ActorDefinition type calss, since it can have many instances
            if (type == typeof(Actor.Builders.ActorDefinition))
            {
                strType += "." + className;
            }

            if (ByTypeString == null)
                ByTypeString = new Dictionary<String, IActorBuilder>();
            else if (ByTypeString.ContainsKey(strType))
                Logging.Logger.GetSingleton().WriteError("ActorFactory::Register():: Actor type already exists: " + strType);

            

            if (AliasToTypeString == null)
                AliasToTypeString = new Dictionary<string, string>();
            else if (AliasToTypeString.ContainsKey(className))
                Logging.Logger.GetSingleton().WriteError("ActorFactoryFactory::Register():: component with class name already exists: " + className);

            ByTypeString.Add(strType, builder);
            AliasToTypeString.Add(className, strType);
        }

        public static void Register(IActorBuilder builder)
        {
            Register(builder.GetType(), builder);
        }

        public static IActorBuilder GetBuilder(String type)
        {
            IActorBuilder builder;
            if (ByTypeString.TryGetValue(type, out builder))
            {
                return builder;
            }
            Logging.Logger.Debug("ActorFactory::Build():: type not found: " + type);
            return null;
        }

        public static T GetBuilder<T>(String type)
        {
            IActorBuilder builder;
            if (ByTypeString.TryGetValue(type, out builder))
            {
                return (T)builder;
            }
            Logging.Logger.Debug("ActorFactory::Build():: type not found: " + type);
            return default(T);
        }

        public static IActor Build(IScene scene, Type type, Vector3 position, Vector3 direction)
        {
            return Build(scene, type.ToString(), position, direction, null);
        }

        public static IActor Build(IScene scene, String type, Vector3 position, Vector3 direction, Parameters args)
        {
            IActorBuilder builder;
            if (ByTypeString.TryGetValue(type, out builder))
            {
                if (args != null)
                    return builder.Build(scene, position, direction);
                else
                    return builder.Build(scene, position, direction, args);
            }
            Logging.Logger.Debug("ActorFactory::Build():: type not found: " + type);

            //we missed whatever we were tryignt o build, lets see if we can find it in our classname list
            String typeStr = TypeStringFromAlias(type);
            if (ByTypeString.TryGetValue(typeStr, out builder))
            {
                if (args != null)
                    return builder.Build(scene, position, direction);
                else
                    return builder.Build(scene, position, direction, args);
            }
            Logging.Logger.Error("ActorFactory::Build():: type for class name not found: " + typeStr);

            return null;
        }

        public static String TypeStringFromAlias(String className)
        {
            if (AliasToTypeString.ContainsKey(className))
                return AliasToTypeString[className];
            Logging.Logger.Error("ActorFactory:: cant find type for class name of " + className);
            return String.Empty;
        }

        public static Boolean DoesExist(string type)
        {
            IActorBuilder builder;
            if (ByTypeString.TryGetValue(type, out builder))
                return true;
            return false;
        }

        public static Dictionary<String, List<ParameterDescription>> GetComponentParameterDescriptions()
        {
            throw new NotImplementedException();
            /*
            Dictionary<String, List<ParameterDescription>> cp = new Dictionary<string, List<ParameterDescription>>();

            foreach (String compName in ByTypeString.Keys)
            {
                IComponent comp = Build(compName);
                try
                {
                    List<ParameterDescription> cpl = comp.GetParameterDescriptions();
                    cp[compName] = cpl;
                }
                catch (Exception ex)
                {
                    //likely, our component doesnt implement the parameter 
                    if (ex.GetType() == typeof(NotImplementedException))
                    {
                        List<ParameterDescription> cpl = new List<ParameterDescription>();
                        cpl.Add(new ParameterDescription("None", "None", typeof(Object), null));
                        cp[compName] = cpl;
                    }
                }
            }

            return cp;
             * */
        }
    }
}